home *** CD-ROM | disk | FTP | other *** search
/ The 640 MEG Shareware Studio 2 / The 640 Meg Shareware Studio CD-ROM Volume II (Data Express)(1993).ISO / clang / pgp20src.zip / KEYADD.C < prev    next >
C/C++ Source or Header  |  1992-09-02  |  19KB  |  626 lines

  1. /*    keyadd.c  - Keyring merging routines for PGP.
  2.     PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
  3.  
  4.     (c) Copyright 1990-1992 by Philip Zimmermann.  All rights reserved.
  5.     The author assumes no liability for damages resulting from the use
  6.     of this software, even if the damage results from defects in this
  7.     software.  No warranty is expressed or implied.
  8.  
  9.     All the source code Philip Zimmermann wrote for PGP is available for
  10.     free under the "Copyleft" General Public License from the Free
  11.     Software Foundation.  A copy of that license agreement is included in
  12.     the source release package of PGP.  Code developed by others for PGP
  13.     is also freely available.  Other code that has been incorporated into
  14.     PGP from other sources was either originally published in the public
  15.     domain or was used with permission from the various authors.  See the
  16.     PGP User's Guide for more complete information about licensing,
  17.     patent restrictions on certain algorithms, trademarks, copyrights,
  18.     and export controls.  
  19. */
  20.  
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #ifdef UNIX
  24. #include <sys/types.h>
  25. #endif
  26. #include <time.h>
  27. #include "mpilib.h"
  28. #include "idea.h"
  29. #include "random.h"
  30. #include "crypto.h"
  31. #include "fileio.h"
  32. #include "keymgmt.h"
  33. #include "genprime.h"
  34. #include "rsagen.h"
  35. #include "mpiio.h"
  36. #include "language.h"
  37. #include "pgp.h"
  38.  
  39. static int ask_to_sign(byte *keyID, char *ringfile);
  40.  
  41. static int newkeys, newsigs, newids, newrvks;
  42.  
  43. void mergesigs (FILE *fkey, char *keyfile, long keypos, FILE *fring,
  44.         char *ringfile, long *pringpos, FILE *out)
  45. /* Merge signatures from userid in fkey (which is keyfile) at keypos with
  46.  * userid from fring (which is ringfile) at ringpos, appending result to out.
  47.  */
  48. {
  49.     long ringuseridpos, ringpos;
  50.     int ringpktlen, keypktlen;
  51.     int status;
  52.     byte ctb;
  53.     int copying;
  54.     byte keyID[KEYFRAGSIZE];
  55.     char userid[256];
  56.  
  57.     /* First, copy the userid packet itself, plus any comments or ctrls */
  58.     ringuseridpos = ringpos = *pringpos;
  59.     fseek (fring, ringpos, SEEK_SET);
  60.     (void) readkeypacket(fring,FALSE,&ctb,NULL,userid,NULL,NULL,
  61.                 NULL,NULL,NULL,NULL,NULL,NULL);
  62.     PascalToC(userid);
  63.     ringpktlen = ftell(fring) - ringpos;
  64.     copyfilepos (fring, out, ringpktlen, ringpos);
  65.     for ( ; ; )
  66.     {    ringpos = ftell(fring);
  67.         status = nextkeypacket (fring, &ctb);
  68.         if (status < 0  ||  is_key_ctb(ctb)  ||  ctb==CTB_USERID  ||
  69.                         is_ctb_type(ctb,CTB_SKE_TYPE))
  70.             break;
  71.         ringpktlen = ftell(fring) - ringpos;
  72.         copyfilepos (fring, out, ringpktlen, ringpos);
  73.     }
  74.     fseek (fring, ringpos, SEEK_SET);
  75.  
  76.     /* Now, ringpos points just past userid packet and ctrl packet. */
  77.     /* Advance keypos to the analogous location. */
  78.     fseek (fkey, keypos, SEEK_SET);
  79.     (void) nextkeypacket (fkey, &ctb);
  80.     for ( ; ; )
  81.     {    keypos = ftell(fkey);
  82.         status = nextkeypacket (fkey, &ctb);
  83.         if (status < 0  ||  is_key_ctb(ctb)  ||  ctb==CTB_USERID  ||
  84.                         is_ctb_type(ctb,CTB_SKE_TYPE))
  85.             break;
  86.     }
  87.     fseek (fkey, keypos, SEEK_SET);
  88.  
  89.     /* Second, copy all keyfile signatures that aren't in ringfile.
  90.      */
  91.  
  92.     copying = FALSE;
  93.     for ( ; ; )
  94.     {    /* Read next sig from keyfile; see if it is in ringfile;
  95.          * set copying true/false accordingly.  If copying is true
  96.          * and it is a signature, copy it.  Loop till hit
  97.          * a new key or userid in keyfile, or EOF.
  98.          */
  99.         keypos = ftell(fkey);
  100.         status = readkeypacket(fkey,FALSE,&ctb,NULL,NULL,NULL,NULL,
  101.                 NULL,NULL,NULL,NULL,keyID,NULL);
  102.         keypktlen = ftell(fkey) - keypos;
  103.         if (status < 0  ||  is_key_ctb (ctb)  ||  ctb==CTB_USERID)
  104.              break;
  105.         if (is_ctb_type(ctb,CTB_SKE_TYPE))
  106.         {    long sig_pos;
  107.             int sig_len;
  108.             /* Set copying true if signature is not in the ringfile */
  109.             copying = (getpubusersig (ringfile, ringuseridpos, keyID, &sig_pos,
  110.                         &sig_len) < 0);
  111.             if (copying)
  112.             {    fprintf (pgpout, PSTR("New signature from keyID %s on userid \"%s\"\n"), 
  113.                     keyIDstring(keyID),EXTERNAL(userid));
  114.                 ++newsigs;
  115.             }
  116.         }
  117.         if (copying  &&  is_ctb_type(ctb,CTB_SKE_TYPE))
  118.         {    copyfilepos (fkey, out, keypktlen, keypos);
  119.             write_trust (out, KC_SIGTRUST_UNDEFINED);
  120.         }
  121.     }
  122.  
  123.     /* Third, for all ring sig's, copy to output */
  124.     fseek (fring, ringpos, SEEK_SET);
  125.     for ( ; ; )
  126.     {    ringpos = ftell(fring);
  127.         status = nextkeypacket (fring, &ctb);
  128.         ringpktlen = ftell(fring) - ringpos;
  129.         if (status < 0  ||  is_key_ctb (ctb)  ||  ctb==CTB_USERID)
  130.              break;
  131.         copyfilepos (fring, out, ringpktlen, ringpos);
  132.     }    /* End of loop for each sig in ringfile */
  133.     fseek (fring, ringpos, SEEK_SET);
  134.     *pringpos = ringpos;
  135. } /* mergesigs */
  136.  
  137.  
  138. void mergekeys (FILE *fkey, char *keyfile, long keypos, FILE *fring,
  139.         char *ringfile, long *pringpos, FILE *out)
  140. /* Merge key from fkey (which is keyfile) at keypos with key from
  141.  * fring (which is ringfile) at ringpos, appending result to out.
  142.  */
  143. {
  144.     long ringkeypos, keykeypos, ringpos;
  145.     int ringpktlen, keypktlen;
  146.     int status;
  147.     byte ctb;
  148.     int copying;
  149.     boolean ring_compromise = FALSE;
  150.     byte userid[256];
  151.  
  152.     /* First, copy the key packet itself, plus any comments or ctrls */
  153.     ringkeypos = ringpos = *pringpos;
  154.     fseek (fring, ringpos, SEEK_SET);
  155.     (void) nextkeypacket(fring, &ctb);
  156.     ringpktlen = ftell(fring) - ringpos;
  157.     copyfilepos (fring, out, ringpktlen, ringpos);
  158.     for ( ; ; )
  159.     {    ringpos = ftell(fring);
  160.         status = nextkeypacket (fring, &ctb);
  161.         if (status < 0  ||  is_key_ctb(ctb)  ||  ctb==CTB_USERID)
  162.             break;
  163.         if (is_ctb_type(ctb, CTB_SKE_TYPE))
  164.             ring_compromise = TRUE;    /* compromise cert on keyring */
  165.         ringpktlen = ftell(fring) - ringpos;
  166.         copyfilepos (fring, out, ringpktlen, ringpos);
  167.     }
  168.     fseek (fring, ringpos, SEEK_SET);
  169.  
  170.     /* Now, ringpos points just past key packet and ctrl packet. */
  171.     /* Advance keypos to the analogous location. */
  172.     fseek (fkey, keypos, SEEK_SET);
  173.     keykeypos = keypos;
  174.     (void) nextkeypacket (fkey, &ctb);
  175.     keypktlen = ftell(fkey) - keypos;    /* for check_key_sig() */
  176.     for ( ; ; )
  177.     {    keypos = ftell(fkey);
  178.         status = nextkeypacket (fkey, &ctb);
  179.         if (status < 0 || ctb == CTB_USERID || is_ctb_type(ctb, CTB_SKE_TYPE))
  180.             break;
  181.     }
  182.     if (!ring_compromise && is_ctb_type(ctb, CTB_SKE_TYPE))
  183.     {    /* found a compromise cert on keyfile that is not in ringfile */
  184.         word32 timestamp;
  185.         byte sig_class;
  186.         int cert_pktlen;
  187.  
  188.         cert_pktlen = ftell(fkey) - keypos;
  189.         if (check_key_sig(fkey, keykeypos, keypktlen, (char *)userid, fkey, keypos,
  190.                 ringfile, (char *)userid, (byte *)×tamp, &sig_class) == 0 &&
  191.                 sig_class == KC_SIGNATURE_BYTE)
  192.         {
  193.             fprintf(pgpout, PSTR("Key revocation certificate from \"%s\".\n"),
  194.                     EXTERNAL((char *)userid));
  195.             copyfilepos (fkey, out, cert_pktlen, keypos);
  196.             ++newrvks;
  197.         }
  198.         else
  199.             fprintf(pgpout, PSTR("\n\007WARNING:  File '%s' contains bad revocation certificate.\n"));
  200.     }
  201.     fseek (fkey, keypos, SEEK_SET);
  202.  
  203.     /* Second, copy all keyfile userid's plus signatures that aren't
  204.      * in ringfile.
  205.      */
  206.  
  207.     copying = FALSE;
  208.     for ( ; ; )
  209.     {    /* Read next userid from keyfile; see if it is in ringfile;
  210.          * set copying true/false accordingly.  If copying is true
  211.          * and it is a userid or a signature, copy it.  Loop till hit
  212.          * a new key in keyfile, or EOF.
  213.          */
  214.         keypos = ftell(fkey);
  215.         status = readkeypacket(fkey,FALSE,&ctb,NULL,(char *)userid,NULL,NULL,
  216.                 NULL,NULL,NULL,NULL,NULL,NULL);
  217.         keypktlen = ftell(fkey) - keypos;
  218.         if (status < 0  ||  is_key_ctb (ctb))
  219.              break;
  220.         if (ctb == CTB_USERID)
  221.         {    long userid_pos;
  222.             int userid_len;
  223.             PascalToC ((char *)userid);
  224.             /* Set copying true if userid is not in the ringfile */
  225.             copying =  (getpubuserid (ringfile, ringkeypos, userid, &userid_pos,
  226.                         &userid_len) < 0);
  227.             if (copying)
  228.             {    fprintf (pgpout, PSTR("New userid: \"%s\".\n"), EXTERNAL((char *)userid));
  229.                 ++newids;
  230.             }
  231.         }
  232.         if (copying)
  233.         {    if (ctb==CTB_USERID  ||  is_ctb_type(ctb,CTB_SKE_TYPE))
  234.             {    copyfilepos (fkey, out, keypktlen, keypos);
  235.                 if (is_ctb_type(ctb,CTB_SKE_TYPE))
  236.                     write_trust (out, KC_SIGTRUST_UNDEFINED);
  237.                 else
  238.                     write_trust (out, KC_LEGIT_UNKNOWN);
  239.             }
  240.         }
  241.     }
  242.  
  243.     /* Third, for all ring userid's, if not in keyfile, copy the userid
  244.      * plus its dependant signatures.
  245.      */
  246.     fseek (fring, ringpos, SEEK_SET);
  247.     for ( ; ; )
  248.     {    ringpos = ftell(fring);
  249.         status = readkeypacket(fring,FALSE,&ctb,NULL,(char *)userid,NULL,NULL,
  250.                     NULL,NULL,NULL,NULL,NULL,NULL);
  251.         ringpktlen = ftell(fring) - ringpos;
  252.         if (status < 0  ||  is_key_ctb (ctb))
  253.              break;
  254.         if (ctb == CTB_USERID)
  255.         {    long userid_pos;
  256.             int userid_len;
  257.             /* See if there is a match in keyfile */
  258.             PascalToC ((char *) userid);
  259.             if (getpubuserid (keyfile, keykeypos, userid, &userid_pos,
  260.                         &userid_len) >= 0)
  261.             {    mergesigs (fkey,keyfile,userid_pos,fring,ringfile,&ringpos,out);
  262.                 copying = FALSE;
  263.             }
  264.             else
  265.                 copying = TRUE;
  266.         }
  267.         if (copying)
  268.         {    /* Copy ringfile userid and sigs to out */
  269.             copyfilepos (fring, out, ringpktlen, ringpos);
  270.         }
  271.     }    /* End of loop for each key in ringfile */
  272.     fseek (fring, ringpos, SEEK_SET);
  273.     *pringpos = ringpos;
  274. } /* mergekeys */
  275.  
  276.  
  277. int addto_keyring(char *keyfile, char *ringfile, boolean query)
  278. /*    Adds (prepends) key file to key ring file.  If query is TRUE, ask
  279.     before doing any actual changes. */
  280. {    FILE *f, *g, *h;
  281.     long file_position,fp;
  282.     int pktlen;    /* unused, just to satisfy getpublickey */
  283.     byte ctb;
  284.     int status;
  285.     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
  286.     unit n1[MAX_UNIT_PRECISION];
  287.     byte keyID[KEYFRAGSIZE];
  288.     byte userid[256];        /* key certificate userid */
  289.     byte userid1[256];
  290.     word32 tstamp; byte *timestamp = (byte *) &tstamp;        /* key certificate timestamp */
  291.     char trans_keyfile[MAX_PATH];
  292.     boolean is_armored = FALSE;
  293.     boolean userid_seen = FALSE;
  294.     int commonkeys = 0;
  295.     int copying;
  296.     struct nkey {
  297.         byte keyID[KEYFRAGSIZE];
  298.         struct nkey *next;
  299.     } *nkey, *nkeys = NULL;
  300.  
  301.     if (build_path(SCRATCH_KEYRING_PATH,SCRATCH_KEYRING_FILENAME,ringfile)<0)
  302.         return(-1);        /* File path too long */
  303.  
  304.     /* check if the keyfile to be added is armored */
  305.     if ((is_armored = is_armor_file(keyfile)) == TRUE)
  306.     {   /* decode it into the actual keyfile */
  307.         boolean changed_name;
  308.         strcpy(trans_keyfile,keyfile);
  309.         keyfile = tempfile(TMP_TMPDIR|TMP_WIPE);
  310.         if (de_armor_file(trans_keyfile,keyfile,&changed_name) < 0)
  311.             return(-1);
  312.     }
  313.  
  314.     userid[0] = '\0';
  315.     if (dokeycheck((char *) userid, keyfile, NULL) < 0)
  316.     {    fprintf(pgpout, PSTR("\007Keyring check error. ") );
  317.         fprintf(pgpout, PSTR("\nKey(s) will not be added to keyring.\n"));
  318.         goto err;
  319.     }
  320.  
  321.     /* open file f for read, in binary (not text) mode...*/
  322. #ifdef VMS
  323.     if ((f = fopen(keyfile,"rb","ctx=stm")) == NULL)
  324. #else
  325.     if ((f = fopen(keyfile,"rb")) == NULL)
  326. #endif
  327.     {    fprintf(pgpout,PSTR("\n\007Can't open key file '%s'\n"),keyfile);
  328.         goto err;
  329.     }
  330.     if (!file_exists(ringfile))
  331.     {    /* ringfile does not exist.  Can it be created? */
  332.         /* open file g for writing, in binary (not text) mode...*/
  333.         g = fopen(ringfile,"wb");
  334.         if (g==NULL)
  335.         {    fprintf(pgpout,PSTR("\nKey ring file '%s' cannot be created.\n"),ringfile);
  336.             fclose(f);
  337.             goto err;
  338.         }
  339.         fclose(g);
  340.     }
  341.  
  342.     /* Create working output file */
  343.     remove(SCRATCH_KEYRING_PATH);
  344.     /* open file g for writing, in binary (not text) mode...*/
  345.     if ((g = fopen(SCRATCH_KEYRING_PATH,"wb")) == NULL)
  346.     {    fclose(f);
  347.         goto err;
  348.     }
  349.     newkeys = newsigs = newids = newrvks = 0;
  350.  
  351.     /* Pass 1 - copy all keys from f which aren't in ring file */
  352.     /* Also copy userid and signature packets. */
  353.     copying = FALSE;
  354.     for ( ; ; )
  355.     {    file_position = ftell(f);
  356.  
  357.         status = readkeypacket(f,FALSE,&ctb,timestamp,(char *)userid,n,e,
  358.                 NULL,NULL,NULL,NULL,NULL,NULL);
  359.         /* Note that readkeypacket has called set_precision */
  360.         if (status == -1)    /* EOF */
  361.             break;
  362.         if (status < 0)
  363.         {    fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"),
  364.                 keyfile);
  365.             fclose(f);    /* close key file */
  366.             goto err;
  367.         }
  368.  
  369.         /* Check to see if key is already on key ring */
  370.         if (is_key_ctb(ctb))
  371.         {
  372.             extract_keyID(keyID, n);    /* from keyfile, not ringfile */
  373.     
  374.             /*    Check for duplicate key in key ring: */
  375.             if (getpublickey(TRUE, FALSE, ringfile, &fp, &pktlen, keyID, timestamp, userid, n1, e) >= 0)
  376.             {    if (mp_compare (n, n1) != 0)
  377.                 {    fprintf(pgpout, PSTR("\n\007Warning: Key ID %s matches key ID of key already on \n\
  378. key ring '%s', but the keys themselves differ.\n\
  379. This is highly suspicious.  This key will not be added to ring.\n\
  380. Acknowledge by pressing return: "), keyIDstring(keyID), ringfile);
  381.                     getyesno('n');
  382.                     fclose(f);    /* close key file */
  383.                     goto err;
  384.                 }
  385.                 else
  386.                 {    if (verbose)
  387.                         fprintf(pgpout,PSTR("Key ID %s is already included in key ring '%s'.\n"),
  388.                             keyIDstring(keyID), ringfile);
  389.                     ++commonkeys;
  390.                 }
  391.                 copying = FALSE;
  392.             }
  393.             else
  394.             {
  395.                 ++newkeys;
  396. #if 0
  397.                 if (query)
  398.                 {    if (is_ctb_type(ctb, CTB_CERT_SECKEY_TYPE))
  399.                         fprintf (pgpout, PSTR ("\nAdd secret key to key ring '%s' (y/N)? "),
  400.                                 ringfile);
  401.                     else
  402.                         fprintf (pgpout, PSTR ("\nAdd public key to key ring '%s' (y/N)? "),
  403.                                 ringfile);
  404.                         
  405.                     if (! getyesno( 'n' ))
  406.                     {    fclose(f);
  407.                         remove(SCRATCH_KEYRING_PATH);
  408.                         return(0);    /* user chose to abort */
  409.                     }
  410.                     query = FALSE;        /* Don't ask subsequently */
  411.                 }
  412. #endif
  413.  
  414.                 if ((nkey = (struct nkey *) malloc(sizeof(struct nkey))) == NULL)
  415.                 {
  416.                     fprintf(stderr, PSTR("\n\007Out of memory.\n"));
  417.                     exitPGP(7);
  418.                 }
  419.                 memcpy(nkey->keyID, keyID, KEYFRAGSIZE);
  420.                 nkey->next = nkeys;
  421.                 nkeys = nkey;
  422.     
  423.                 fprintf(pgpout, PSTR("New key ID: %s\n"), keyIDstring(keyID));
  424.                 copying = TRUE;
  425.             }
  426.         }
  427.         /* Now, we copy according to the copying flag */
  428.         /*    The key is prepended to the ring to give it search precedence
  429.             over other keys with that same userid. */
  430.     
  431.         if (copying  &&  (is_key_ctb(ctb) || ctb==CTB_USERID ||
  432.                                 is_ctb_type(ctb,CTB_SKE_TYPE)))
  433.         {    pktlen = (int) (ftell(f) - file_position);
  434.             copyfilepos(f,g,pktlen,file_position);    /* copy packet from f */
  435.             /* Initialize trust packets after keys and signatures */
  436.             if (is_key_ctb(ctb))
  437.             {
  438.                 write_trust (g, KC_OWNERTRUST_UNDEFINED);
  439.                 userid_seen = FALSE;
  440.             }
  441.             else if (is_ctb_type(ctb,CTB_SKE_TYPE))
  442.             {
  443.                 if (userid_seen)
  444.                     write_trust (g, KC_SIGTRUST_UNDEFINED);
  445.                 else
  446.                 /* signature certificate before userid must be compromise cert. */
  447.                     fprintf(pgpout, PSTR("Key has been revoked.\n"));
  448.             }
  449.             else if (is_ctb_type(ctb,CTB_USERID_TYPE))
  450.             {
  451.                 write_trust (g, KC_LEGIT_UNKNOWN);
  452.                 userid_seen = TRUE;
  453.             }
  454.         }
  455.     }
  456.  
  457.     /* Now copy the remainder of the ringfile, h, to g.  commonkeys tells
  458.         how many keys are common to keyfile and ringfile.  As long as that is
  459.         nonzero we will check each key in ringfile to see if it has a match
  460.         in keyfile.
  461.     */
  462. #ifdef VMS
  463.     if ((h = fopen(ringfile,"rb","ctx=stm")) != NULL)
  464. #else
  465.     if ((h = fopen(ringfile,"rb")) != NULL)
  466. #endif
  467.     {    while (commonkeys)        /* Loop for each key in ringfile */
  468.         {    file_position = ftell(h);
  469.             status = readkeypacket(h,FALSE,&ctb,NULL,(char *)userid,n,e,
  470.                         NULL,NULL,NULL,NULL,NULL,NULL);
  471.             if (status < 0)
  472.             {    if (status == -1)
  473.                     fprintf(pgpout, PSTR("\n\007Key file contains duplicate keys: cannot be added to keyring\n"));
  474.                 else
  475.                     fprintf(pgpout,PSTR("\n\007Could not read key from file '%s'.\n"),
  476.                         ringfile);
  477.                 fclose(f);
  478.                 fclose(g);
  479.                 fclose(h);
  480.                 goto err;
  481.             }
  482.             PascalToC ((char *) userid);
  483.             pktlen = ftell(h) - file_position;
  484.             if (is_key_ctb(ctb))
  485.             {    long    tfp;
  486.                 int        tpktlen;
  487.                 /* See if there is a match in keyfile */
  488.                 extract_keyID(keyID, n);    /* from ringfile, not keyfile */
  489.                 if ((getpublickey(TRUE, FALSE, keyfile, &tfp, &tpktlen,
  490.                      keyID, timestamp, userid1, n1, e) >= 0)  &&
  491.                         (mp_compare(n, n1) == 0))
  492.                 {    
  493.                     if (verbose)
  494.                         fprintf (pgpout, PSTR("Merging key ID: %s\n"),keyIDstring(keyID));
  495.                     mergekeys (f,keyfile,tfp, h,ringfile,&file_position, g);
  496.                     copying = FALSE;
  497.                     --commonkeys;
  498.                 }
  499.                 else
  500.                     copying = TRUE;
  501.             }
  502.             if (copying)
  503.             {    /* Copy ringfile key to g, without its sigs */
  504.                 copyfilepos (h,g,pktlen,file_position);
  505.                 file_position += pktlen;
  506.             }
  507.         }    /* End of loop for each key in ringfile */
  508.         copyfile(h,g,-1L);    /* copy rest of file from file h to g */
  509.         fclose(h);
  510.     }
  511.     fclose(f);
  512.     fclose(g);
  513.     if (newsigs == 0 && newkeys == 0 && newids == 0 && newrvks == 0)
  514.     {
  515.         fprintf(pgpout, PSTR("No new keys or signatures in keyfile.\n"));
  516.         remove(SCRATCH_KEYRING_PATH);
  517.         return(0);
  518.     }
  519.  
  520.     for (nkey = nkeys; nkey; nkey = nkey->next)
  521.     {
  522.         if (dokeycheck(NULL, SCRATCH_KEYRING_PATH, nkey->keyID))
  523.             goto err;
  524.     }
  525.     fprintf(pgpout, PSTR("\nKeyfile contains:\n"));
  526.     if (newkeys)
  527.         fprintf(pgpout, PSTR("%4d new key(s)\n"), newkeys);
  528.     if (newsigs)
  529.         fprintf(pgpout, PSTR("%4d new signatures(s)\n"), newsigs);
  530.     if (newids)
  531.         fprintf(pgpout, PSTR("%4d new user ID(s)\n"), newids);
  532.     if (newrvks)
  533.         fprintf(pgpout, PSTR("%4d new revocation(s)\n"), newrvks);
  534.     if (query)
  535.     {
  536.         fprintf(pgpout, PSTR("\nDo you want to add this keyfile to keyring '%s' (y/N)? "), ringfile);
  537.         if (!getyesno('n'))
  538.         {    remove(SCRATCH_KEYRING_PATH);
  539.             return(1);
  540.         }
  541.     }
  542.     if ((status = maintenance(SCRATCH_KEYRING_PATH, MAINT_SILENT)) == 0)
  543.         for (nkey = nkeys; nkey; nkey = nkey->next)
  544.         {    fprintf(pgpout,PSTR("Adding key ID %s from file '%s' to key ring '%s'.\n"),
  545.                 keyIDstring(nkey->keyID),(is_armored?trans_keyfile:keyfile),ringfile);
  546.             ask_to_sign(nkey->keyID, SCRATCH_KEYRING_PATH);
  547.         }
  548.  
  549.     backup_rename(SCRATCH_KEYRING_PATH,ringfile);
  550.  
  551.     if (is_armored)
  552.         rmtemp(keyfile);    /* zap decoded keyfile */
  553.     return(0);    /* normal return */
  554.  
  555. err:
  556.     /* make sure we remove any garbage files we may have created */
  557.     if (is_armored)
  558.         rmtemp(keyfile);    /* zap decoded keyfile */
  559.     remove(SCRATCH_KEYRING_PATH);
  560.     return(-1);
  561. }    /* addto_keyring */
  562.  
  563.  
  564. static int ask_to_sign(byte *keyID, char *ringfile)
  565. {
  566.     FILE *f;
  567.     word32 timestamp;
  568.     byte ctb, trust;
  569.     unit n[MAX_UNIT_PRECISION], e[MAX_UNIT_PRECISION];
  570.     byte userid[256];
  571.     long fpos;
  572.     int pktlen;    /* unused, just to satisfy getpublickey */
  573.     int status;
  574.     extern char my_name[];
  575.  
  576.     if (getpublickey(TRUE, FALSE, ringfile, &fpos, &pktlen, 
  577.             keyID, (byte *)×tamp, userid, n, e) < 0)
  578.         return(-1);
  579.  
  580.     if ((f = fopenbin(ringfile, "r")) == NULL)
  581.         return(-1);
  582.  
  583.     fseek(f, fpos, SEEK_SET);
  584.     if (is_compromised(f))
  585.     {    fclose(f);
  586.         return(0);
  587.     }
  588.     if (nextkeypacket(f, &ctb) < 0)
  589.     {    fclose(f);
  590.         return(-1);
  591.     }
  592.     if (ctb != CTB_CERT_PUBKEY)
  593.     {    fclose(f);
  594.         return(0);    /* don't ask to sign secret key */
  595.     }
  596.     while (nextkeypacket(f, &ctb) == 0 && !is_key_ctb(ctb))
  597.         if (ctb == CTB_USERID)    /* check first userid */
  598.             break;
  599.     if (ctb != CTB_USERID)
  600.     {
  601.         fclose(f);
  602.         return(-1);
  603.     }
  604.  
  605.     if ((status = read_trust(f, &trust)) < 0)
  606.     {
  607.         fclose(f);
  608.         return(status);
  609.     }
  610.     if ((trust & KC_LEGIT_MASK) == KC_LEGIT_COMPLETE)
  611.     {
  612.         fclose(f);
  613.         return(0);
  614.     }
  615.     show_key(f, fpos, SHOW_ALL);
  616.     fclose(f);
  617.     PascalToC((char *)userid);
  618.     fprintf(pgpout, PSTR("\nDo you want to certify this key yourself (y/N)? "));
  619.     if (getyesno('n'))
  620.     {
  621.         if (signkey((char *)userid, my_name, ringfile) == 0)
  622.             maintenance(ringfile, MAINT_SILENT);
  623.     }
  624.     return(0);
  625. }
  626.